﻿using System;
using System.Security.Cryptography;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SjclHelpers.Codec;

namespace SjclHelpersTests.Codec
{
    [TestClass]
    public class BinaryNotationConverterTests
    {
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //  bitArray to hex...
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        [TestMethod]
        public void ToHex_BitArray_Hex()
        {
            // Fixture setup...
            var bitArray = new[] {
                // res of sjcl.hash.sha256("bitarraytests");
                -238462247, -1720858987, 358066564,
                1525486630, 1841166455, -736397817,
                -1715646032, 1172390430
            };
            var exptectedHex =
                "f1c95ad9996dc6951557a9845aed14266dbdf877d41b760799bd51b045e1421e";

            // Exercise SUT...
            var actualHex = bitArray.ToHex();

            // Verify SUT...
            Assert.AreEqual(exptectedHex, actualHex);
        }

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //  bitArray to bytes...
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        [TestMethod]
        public void ToBytes_Works()
        {
            // Fixture setup...
            var bitArray = new[] {
                // res of sjcl.hash.sha256("bitarraytests");
                -238462247, -1720858987, 358066564,
                1525486630, 1841166455, -736397817,
                -1715646032, 1172390430
            };
            var hashSrc = Encoding.UTF8.GetBytes("bitarraytests");
            var exptectedBytes = SHA256.Create().ComputeHash(hashSrc);
        
            // Exercise SUT...
            var actualBytes = bitArray.ToBytes();
        
            // Verify SUT...
            CollectionAssert.AreEqual(exptectedBytes, actualBytes);
        }

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //  hex to bytes...
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ToBytes_StringNull_ArgumentNullException()
        {
            // Fixture setup...
            string hex = null;

            // Exercise and verify SUT...
            hex.ToBytes();
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ToBytes_NotEven_ArgumentOutOfRangeException()
        {
            // Fixture setup...
            var hex = "0";

            // Exercise and verify SUT...
            hex.ToBytes();
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void ToBytes_NotAHex_ArgumentOutOfRangeException()
        {
            // Fixture setup...
            var hex = "g ";

            // Exercise and verify SUT...
            hex.ToBytes();
        }

        [TestMethod]
        public void ToBytes_EmptyHex_EmptyBytes()
        {
            // Fixture setup...
            const string hex = "";

            // Exercise SUT...
            var bytes = hex.ToBytes();

            // Verify SUT...
            CollectionAssert.AreEqual(new byte[0], bytes);
        }

        [TestMethod]
        public void ToBytes_ValidHex_CorrectBytes()
        {
            // Fixture setup...
            const string hex = "00ff";

            // Exercise SUT...
            var bytes = hex.ToBytes();

            // Verify SUT...
            CollectionAssert.AreEqual(new byte[] { 0, 255 }, bytes);
        }

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //  hex to base64...
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        [TestMethod]
        public void ToBase64_Works()
        {
            // Fixture setup...
            const string hex = "3e84cba87633f78cbb14c81648c3ad67";
            const string expectedBase64 = "PoTLqHYz94y7FMgWSMOtZw==";

            // Exercise SUT...
            var actualBase64 = hex.ToBase64();

            // Verify SUT...
            Assert.AreEqual(expectedBase64, actualBase64);
        }

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //  byte to hex...
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        [TestMethod]
        public void ToHex_Bytes_Hex()
        {
            // Fixture setup...
            var bytes = new byte[] { 0, 255 };
            const string expectedHex = "00ff";

            // Exercise SUT...
            var actualHex = bytes.ToHex();

            // Verify SUT...
            Assert.AreEqual(expectedHex, actualHex);
        }
    }
}
